/* -+- file  ./kf2/Events/EventBox.cs -+- */
/*
 * kf2 jabber client
 * ~~~~~~~~~~~~~~~~~
 *
 * Copyright (C) 2006-2007 Przemysław Sitek
 * 				<przemyslaw.sitek at wp.pl> 
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this program; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

using System;
using System.Collections;
using System.Collections.Generic;
using Habazie.kf2.Core;
using Habazie.kf2.Net;
using Habazie.kf2.GUI;

namespace Habazie.kf2.Events
{
	
	public class EventBox : IEnumerable
	{
		///<summary>Event queue</summary>
		private LinkedList<Event> m_Events;
		
//		private bool m_AutoDispatch = false;
		
		public event System.EventHandler Updated;
		
		private App m_App;
		
		public EventBox (App a)
		{
			m_Events = new LinkedList<Event> ();
			m_App = a;
		}
		
		public IEnumerator GetEnumerator ()
		{
			return m_Events.GetEnumerator ();
		}
		
		#region Event queue
		
		public void Enqueue (Event e)
		{
			m_Events.AddLast (e);
			
			if (Updated != null)
				Updated (this, new System.EventArgs ());
		}
		
		
		public Event Dequeue ()
		{
			Event e = Peek ();
			m_Events.RemoveFirst ();

			if (Updated != null)
				Updated (this, new System.EventArgs ());
			return e;
		}
		
		
		public Event Peek ()
		{
			if (m_Events.Count > 0)
				return m_Events.First.Value;
			else
				return null;
		}
		
		
		// TODO
		public Event Peek (jabber.JID jid)
		{
		//	foreach (Event e in m_Events) {
		//	}
			return null;
		}
		
		public Event Get (int id) {
			foreach (Event e in m_Events) {
				if (e.Id == id) {
					m_Events.Remove (e);
					if (Updated != null)
						Updated (this, new System.EventArgs ());
					return e;
				}
			}
			return null;
		}
		
		public ChatEvent GetChatEvent (Account a, jabber.JID j)
		{
			foreach (Event e in m_Events) {
				ChatEvent ce;
				if ((ce = e as ChatEvent) != null)
					if (ce.Source == a && ce.GetJID () == j)
						return ce;
			}
			return null;
		}
		
		public int Count {
			get { return m_Events.Count; }
		}
		
		#endregion
		#region Event dispatching mechanism
		
		public void Dispatch (Account acc, jabber.protocol.client.Presence presence)
		{
			if (presence.Type == jabber.protocol.client.PresenceType.available)
				m_App.NotifyService.Notify (NotifyClass.UserOnline, presence.From, presence.Show + ": " + presence.Status);
				
			else if (presence.Type == jabber.protocol.client.PresenceType.unavailable)
				m_App.NotifyService.Notify (NotifyClass.UserOffline, presence.From, "offline");
				
			else if (presence.Type == jabber.protocol.client.PresenceType.subscribe) {
				if (Util.Config.GetBool ("auto-authorize")) {
					
					/* Automagically authorize subscription requests */
					jabber.protocol.client.Presence p = new jabber.protocol.client.Presence (acc.Document);
					p.To = presence.From;
					p.Type = jabber.protocol.client.PresenceType.subscribed;
					acc.Write (p);
				} else {
					Event e = new SubscribeEvent (acc, presence);
					Dispatch (e);
				}
			}				
		}
		
		public void Dispatch (Account acc, jabber.protocol.client.Message message)
		{
			/* TODO: Filter message */
			/* TODO: Archive message */
			m_App.ArchivingService.Archive (acc, message as Message, message.From.Bare, true);
			
			Event e;
			if (message.Type == jabber.protocol.client.MessageType.chat) {
				e = new ChatEvent (acc, message);
			} else {
				e = new MessageEvent (acc, message);
			}
			
			Dispatch (e);
		}
		
		public void Dispatch (Event e)
		{
			/* TODO: notify */
			e.Notify (m_App.NotifyService);
			Console.WriteLine ("Got event to be dispatched...");
			
			/* Check if we want to auto dispatch this event */
			if (Util.Config.GetBool ("auto-popup-events")) {
				e.Display ();
				return;
			}
			
			/* Chat... */
			ChatEvent ce;
			if ((ce = (e as ChatEvent)) != null) {
				Chat c = Chat.GetIfExists (ce.Source, ce.GetJID ());
				if (c != null) {
					ce.Display ();
				} else {
					/* Have we chats queried? */
					ChatEvent pe = GetChatEvent (ce.Source, ce.GetJID ());
					if (pe != null) {
						pe.Push (ce.Msg);
						//Enqueue (pe);
					} else {
						Enqueue (e);
					}
				}
			} else {
				Enqueue (e);
			}			
		}
		
		///<summary>Process event with id</summary>
		public void Process (int id)
		{
			Event e = Get (id);
			if (e != null)
				e.Display ();
		}
		
		#endregion
	}
}
